package com.glsc.ngateway.platform.service.cmdb;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.glsc.ngateway.common.base.domain.mysql.cmdb.*;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.flow.cmdb.FlowFormDeviceIn;
import com.glsc.ngateway.common.base.exception.PlatformException;
import com.glsc.ngateway.common.base.repo.mysql.cmdb.CmdbChangeLogRepository;
import com.glsc.ngateway.common.base.repo.mysql.cmdb.CmdbDeviceDetailRepository;
import com.glsc.ngateway.common.base.repo.mysql.gateway.platform.flow.cmdb.FlowFormDeviceInRepo;
import com.glsc.ngateway.platform.utils.AssertOverride;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

import static com.glsc.ngateway.common.api.common.enums.DictConstant.*;

@Service
public class CmdbDeviceDetailService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private SequenceProductService sequenceProductService;
    @Autowired
    private CmdbDeviceDetailRepository cmdbDeviceDetailRepository;
    @Autowired
    private CmdbChangeLogRepository cmdbChangeLogRepository;
    @Autowired
    private CmdbDeviceStandardService cmdbDeviceStandardService;
    @Autowired
    private CmdbCpuDetailService cmdbCpuDetailService;
    @Autowired
    private CmdbMemoryDetailService cmdbMemoryDetailService;
    @Autowired
    private CmdbDiskDetailService cmdbDiskDetailService;
    @Autowired
    private CmdbPartDetailService cmdbPartDetailService;
    @Autowired
    private FlowFormDeviceInRepo flowFormDeviceInRepo;


    public Object search(String type, Object paramsObj) {
        JSONObject objParmams = JSONObject.parseObject(JSONObject.toJSONString(paramsObj)).entrySet().stream()
                .filter(entry -> !entry.getValue().toString().isEmpty())
                .collect(JSONObject::new, (obj, entry) -> obj.put(entry.getKey(), entry.getValue()), JSONObject::putAll);

        if (StrUtil.isEmpty(objParmams.getString("orderByDirection"))) {
            objParmams.put("orderByDirection", "DESC");
        }
        if (StrUtil.isEmpty(objParmams.getString("orderByField"))) {
            objParmams.put("orderByField", "id");
        }
        Sort sort = Sort.by(Sort.Direction.fromString(objParmams.getString("orderByDirection")), objParmams.getString("orderByField"));

        Pageable pageable = PageRequest.of(objParmams.getInteger("pageNo") - 1, objParmams.getInteger("pageSize"), sort);

        if (CMDB_DEVICE_DETAIL.equals(type)) {
            CmdbDeviceDetail paramSearchDto = JSONObject.parseObject(JSONObject.toJSONString(objParmams), CmdbDeviceDetail.class);
            Page<CmdbDeviceDetail> result = cmdbDeviceDetailRepository.searchByParam(pageable, paramSearchDto);
            return result;
        }


        return null;
    }

    /**
     * @param cmdbDeviceDetail
     * @param account          操作人员
     * @param cmdbConfirm
     */
    public void addOrUpdate(CmdbDeviceDetail cmdbDeviceDetail, String account, String cmdbConfirm) {
        int addOrUpdateFlag = 0;
        cmdbDeviceDetail.setIsDelete(NO_DELETE);
        CmdbChangeLog log = new CmdbChangeLog();
        if (cmdbDeviceDetail.getDeviceDetailId() != null) {
            //修改
            log.setChangeType(UPDATE_STRING);
            if (cmdbDeviceDetail.getLifeStatus() != LIFE_CYCLE_OUT){
                //报废的时候不删除
                deviceDetailWithPartInDelete(cmdbDeviceDetail.getDeviceDetailId(),account);
            }
            addOrUpdateFlag = 2;
        } else {
            //新增
            log.setChangeType(ADD_STRING);
            //自动生成编号
            String code = sequenceProductService.buildSequence(CMDB_DEVICE_DETAIL);
            cmdbDeviceDetail.setDeviceDetailCode(code);
            //将规格里的参数填充到明细中
            CmdbDeviceStandard deviceStandard = cmdbDeviceStandardService.findByDeviceStandardCode(cmdbDeviceDetail.getDeviceStandardCode());
            cmdbDeviceDetail.setUAmount(deviceStandard.getUAmount());
            cmdbDeviceDetail.setCpuPortAmount(deviceStandard.getCpuPortAmount());
            cmdbDeviceDetail.setMemoryPortAmount(deviceStandard.getMemoryPortAmount());
            cmdbDeviceDetail.setDiskPortAmount(deviceStandard.getDiskPortAmount());
            cmdbDeviceDetail.setPciPortAmount(deviceStandard.getPciPortAmount());
            cmdbDeviceDetail.setElePortAmount(deviceStandard.getElePortAmount());
            addOrUpdateFlag = 1;
        }
        if (addOrUpdateFlag != 0){
            checkUnique(cmdbDeviceDetail,addOrUpdateFlag,cmdbConfirm);
        }
        log.setChangeContent(JSONObject.toJSONString(cmdbDeviceDetail));
        log.setChangeFrom(CMDB_DEVICE_DETAIL);
        log.setChangeId(cmdbDeviceDetail.getDeviceDetailId() != null ? cmdbDeviceDetail.getDeviceDetailId().toString() : null);
        log.setChangeUser(account);
        cmdbChangeLogRepository.save(log);
        cmdbDeviceDetailRepository.save(cmdbDeviceDetail);
    }

    private void checkUnique(CmdbDeviceDetail cmdbDeviceDetail, int addOrUpdateFlag, String cmdbConfirm) {
        if (StrUtil.isNotEmpty(cmdbDeviceDetail.getSn())){
            if (addOrUpdateFlag == 1){
                findSame(cmdbDeviceDetail,cmdbConfirm);
            } else {
                //修改情况，要把已有结果查询出来，如果有变化还要校验
                Optional<CmdbDeviceDetail> result = cmdbDeviceDetailRepository.findById(cmdbDeviceDetail.getDeviceDetailId());
                if (result.isPresent()){
                    if (result.get().getSn() != null && ! result.get().getSn().equals(cmdbDeviceDetail.getSn())){
                        if (result.get().getIsDelete().equals(NO_DELETE)){
                            findSame(cmdbDeviceDetail,cmdbConfirm);
                        }
                    }
                    //修改情况存在未删除的记录
                } else {
                    findSame(cmdbDeviceDetail,cmdbConfirm);
                }
            }

        }
    }

    public void findSame(CmdbDeviceDetail cmdbDeviceDetail, String cmdbConfirm) {
        List<CmdbDeviceDetail> result = cmdbDeviceDetailRepository.findAllBySnAndIsDelete(cmdbDeviceDetail.getSn(), NO_DELETE);
        if (CollectionUtil.isNotEmpty(result)){
            throw PlatformException.errorWithOutMail("序列号重复");
        }
        //已经发起流程的重复sn也不行
        if (!StrUtil.equals(CMDB_CONFIRM,cmdbConfirm)){
            List<FlowFormDeviceIn> flowFormDeviceInDetails = flowFormDeviceInRepo.findFlowSn(cmdbDeviceDetail.getSn());
            if (CollectionUtil.isNotEmpty(flowFormDeviceInDetails)){
                throw PlatformException.errorWithOutMail("有发起过的流程"+flowFormDeviceInDetails.get(0).getProcessTitle()+"存在相同的设备序列号");
            }
        }
    }

    /**
     * 删除已经入库的明细
     * @param deviceDetailId
     */
    private void deviceDetailWithPartInDelete(Integer deviceDetailId,String operator) {
        cmdbCpuDetailService.deleteByDeviceDetailId(deviceDetailId,operator);
        cmdbMemoryDetailService.deleteByDeviceDetailId(deviceDetailId,operator);
        cmdbDiskDetailService.deleteByDeviceDetailId(deviceDetailId,operator);
        cmdbPartDetailService.deleteByDeviceDetailId(deviceDetailId,operator);
    }

    /**
     * 同时配件明细入库
     *
     * @param h
     * @param operator
     */
    public void deviceDetailWithPartIn(CmdbDeviceDetail h, String operator,String cmdbConfirm) {
        String deviceStandardCode = h.getDeviceStandardCode();
        logger.info("deviceStandardCode:"+deviceStandardCode);
        //查询对应规格信息
        CmdbDeviceStandard deviceStandard = cmdbDeviceStandardService.findByDeviceStandardCode(deviceStandardCode);
//        BeanUtil.copyProperties(deviceStandard,h);
//        this.addOrUpdate(h,operator);
        //cpu
        if (deviceStandard.getCpuStandard() != null){
            CmdbCpuDetail cpuDetail = new CmdbCpuDetail();
            BeanUtil.copyProperties(deviceStandard.getCpuStandard(),cpuDetail);
            cpuDetail.setDeviceCode(h.getDeviceDetailCode());
            cpuDetail.setManufactDate(h.getManufactDate());
            cpuDetail.setExpirateDate(h.getExpirateDate());
            //全金星 10-18 16:12:46如果是入库直接报废的就只有位置id了，没有设备明细id.已分配之后报废的就只有设备明细id，没有位置id
//        cpuDetail.setLocationId(h.getMachineRoomId());
            cpuDetail.setLifeStatus(PART_LIFE_CYCLE_ASSGIN);
            //按照数量插入
            for (int i = 0; i < deviceStandard.getCpuAmount(); i++) {
                //新增，将jpa自动填充的id去除，否则会被认为是修改
                cpuDetail.setCpuDetailId(null);
                cmdbCpuDetailService.addOrUpdateCpuDetail(cpuDetail,operator, cmdbConfirm);
            }
        }
        //内存
        if (deviceStandard.getMemoryStandard() != null){
            CmdbMemoryDetail memoryDetail = new CmdbMemoryDetail();
            BeanUtil.copyProperties(deviceStandard.getMemoryStandard(),memoryDetail);
            memoryDetail.setDeviceCode(h.getDeviceDetailCode());
            memoryDetail.setManufactDate(h.getManufactDate());
            memoryDetail.setExpirateDate(h.getExpirateDate());
            //全金星 10-18 16:12:46如果是入库直接报废的就只有位置id了，没有设备明细id.已分配之后报废的就只有设备明细id，没有位置id
//        memoryDetail.setLocationId(h.getMachineRoomId());
            memoryDetail.setLifeStatus(PART_LIFE_CYCLE_ASSGIN);
            for (int i = 0; i < deviceStandard.getMemoryAmount(); i++) {
                //新增，将jpa自动填充的id去除，否则会被认为是修改
                memoryDetail.setMemoryDetailId(null);
                cmdbMemoryDetailService.addOrUpdateMemoryDetail(memoryDetail,operator, cmdbConfirm);
            }
        }
        //硬盘
        if (CollectionUtil.isNotEmpty(deviceStandard.getDiskStandardRelate())){
            for (CmdbDiskStandardDeviceStandardRelate diskRelate:deviceStandard.getDiskStandardRelate()) {
                CmdbDiskStandard diskStandard = diskRelate.getCmdbDiskStandard();
                CmdbDiskDetail diskDetail = new CmdbDiskDetail();
                BeanUtil.copyProperties(diskStandard,diskDetail);
                diskDetail.setDeviceCode(h.getDeviceDetailCode());
                diskDetail.setManufactDate(h.getManufactDate());
                diskDetail.setExpirateDate(h.getExpirateDate());
                //全金星 10-18 16:12:46如果是入库直接报废的就只有位置id了，没有设备明细id.已分配之后报废的就只有设备明细id，没有位置id
//            diskDetail.setLocationId(h.getMachineRoomId());
                diskDetail.setLifeStatus(PART_LIFE_CYCLE_ASSGIN);
                for (int i = 0; i < diskRelate.getAmount(); i++) {
                    //新增，将jpa自动填充的id去除，否则会被认为是修改
                    diskDetail.setDiskDetailId(null);
                    cmdbDiskDetailService.addOrUpdateDiskDetail(diskDetail,operator, cmdbConfirm);
                }
            }
        }
        //配件
        if (CollectionUtil.isNotEmpty(deviceStandard.getPartStandardRelate())){
            for (CmdbPartStandardDeviceStandardRelate partRelate:deviceStandard.getPartStandardRelate()) {
                CmdbPartStandard partStandard = partRelate.getCmdbPartStandard();
                CmdbPartDetail partDetail = new CmdbPartDetail();
                BeanUtil.copyProperties(partStandard,partDetail);
                partDetail.setDeviceCode(h.getDeviceDetailCode());
                partDetail.setManufactDate(h.getManufactDate());
                partDetail.setExpirateDate(h.getExpirateDate());
                //全金星 10-18 16:12:46如果是入库直接报废的就只有位置id了，没有设备明细id.已分配之后报废的就只有设备明细id，没有位置id
//            partDetail.setLocationId(h.getMachineRoomId());
                partDetail.setLifeStatus(PART_LIFE_CYCLE_ASSGIN);
                for (int i = 0; i < partRelate.getAmount(); i++) {
                    //新增，将jpa自动填充的id去除，否则会被认为是修改
                    partDetail.setPartDetailId(null);
                    cmdbPartDetailService.addOrUpdatePartDetail(partDetail,operator, cmdbConfirm);
                }
            }
        }
    }

    public void delete(CmdbDeviceDetail cmdbDeviceDetail, String account) {
        CmdbChangeLog log = new CmdbChangeLog();
        log.setChangeContent(JSONObject.toJSONString(cmdbDeviceDetail));
        log.setChangeFrom(CMDB_DEVICE_DETAIL);
        log.setChangeId(cmdbDeviceDetail.getDeviceDetailId().toString());
        log.setChangeUser(account);
        log.setChangeType(DELETE_STRING);
        Optional<CmdbDeviceDetail> optional = cmdbDeviceDetailRepository.findById(cmdbDeviceDetail.getDeviceDetailId().intValue());
        if (optional.isPresent()) {
            CmdbDeviceDetail bean = optional.get();
            bean.setIsDelete(DELETED);
            cmdbDeviceDetailRepository.save(bean);
            cmdbChangeLogRepository.save(log);
        } else {
            throw PlatformException.errorWithOutMail("删除记录不存在");
        }
    }

    public void deleteByCodeList(List<String> codes, String account) {
        CmdbChangeLog log = new CmdbChangeLog();
        log.setChangeContent(JSONObject.toJSONString(codes));
        log.setChangeFrom(CMDB_DEVICE_DETAIL);
        log.setChangeUser(account);
        log.setChangeType(DELETE_BATCH_STRING);
        cmdbChangeLogRepository.save(log);
        cmdbDeviceDetailRepository.updateIsDeleteByCodes(DELETED, codes);

    }

    public List<CmdbDeviceDetail> queryAll() {
        return cmdbDeviceDetailRepository.findAllByIsDelete(NO_DELETE);
    }

    /**
     * 根据序列号查询设备明细
     *
     * @return
     */
    public List<CmdbDeviceDetail> listBySn(List<String> snList) {
        return cmdbDeviceDetailRepository.findAllBySnIn(snList);
    }

    /**
     * 根据deviceDetailCodeList查询设备明细
     *
     * @return
     */
    public List<CmdbDeviceDetail> listByDetailCode(List<String> deviceDetailCodeList) {
        return cmdbDeviceDetailRepository.findAllByDeviceDetailCodeIn(deviceDetailCodeList);
    }

    public CmdbDeviceDetail findByDeviceDetailCode(String deviceDetailCode) {
        AssertOverride.hasLength(deviceDetailCode,"设备明细号为空");
        CmdbDeviceDetail device = cmdbDeviceDetailRepository.findOneByDeviceDetailCode(deviceDetailCode);
        //填充关联信息
        CmdbDeviceStandard standard = cmdbDeviceStandardService.findByDeviceStandardCode(device.getDeviceStandardCode());
        device.setCmdbDeviceStandard(standard);
        return device;
    }

    /**
     * 设备报废，对应配件也报废
     * @param h
     * @param operator
     */
    public void deviceDetailWithPartOut(CmdbDeviceDetail h, String operator) {
        cmdbCpuDetailService.outByDeviceDetail(h,operator);
        cmdbMemoryDetailService.outByDeviceDetail(h,operator);
        cmdbDiskDetailService.outByDeviceDetail(h,operator);
        cmdbPartDetailService.outByDeviceDetail(h,operator);
    }
}
